using Godot;

namespace MyCraft2;

public partial class World
{
    private void _on_line_edit_day_time_change(float newDayTime)
    {
        DayTime = newDayTime;
    }
}

[Tool]
public partial class World : Node3D
{
    public const float HoursInDay = 24.0f;
    public const int DaysInYear = 365;

    private float _dayTime;

    // 为了简化本地时间，完全跳过经度处理
    [Export(PropertyHint.Range, "0,24,0.0001")]
    public float DayTime
    {
        get => _dayTime;
        set
        {
            _dayTime = value;
            switch (_dayTime)
            {
                case < 0.0f:
                    _dayTime += HoursInDay;
                    DayOfYear--;
                    break;
                case > HoursInDay:
                    _dayTime -= HoursInDay;
                    DayOfYear++;
                    break;
            }

            UpdateAll();
        }
    }

    private float _latitude;

    [Export(PropertyHint.Range, "-90,90,0.01")]
    public float Latitude
    {
        get => _latitude;
        set
        {
            _latitude = value;
            UpdateAll();
        }
    }

    // 一年中的第几天（游戏中到达365天后不建议重置为0以保持月亮位置正确）
    [Export(PropertyHint.Range, "1,365,1")]
    public int DayOfYear
    {
        get => _dayOfYear;
        set
        {
            _dayOfYear = value;
            UpdateAll();
        }
    }

    private int _dayOfYear = 1;

    // 行星轴倾角（导致季节变化）
    [Export(PropertyHint.Range, "-180,180,0.01")]
    public float PlanetAxialTilt
    {
        get => _planetAxialTilt;
        set
        {
            _planetAxialTilt = value;
            UpdateAll();
        }
    }

    private float _planetAxialTilt = 23.44f;

    // 月球轨道与地球轨道的偏差
    [Export(PropertyHint.Range, "-180,180,0.01")]
    public float MoonOrbitalInclination
    {
        get => _moonOrbitalInclination;
        set
        {
            _moonOrbitalInclination = value;
            UpdateMoon();
        }
    }

    private float _moonOrbitalInclination = 5.14f;

    // 月球绕地球公转周期（以天为单位）
    [Export(PropertyHint.Range, "0.1,365,0.01")]
    public float MoonOrbitalPeriod
    {
        get => _moonOrbitalPeriod;
        set
        {
            _moonOrbitalPeriod = value;
            UpdateMoon();
        }
    }

    private float _moonOrbitalPeriod = 29.5f;

    [Export(PropertyHint.Range, "0,1,0.01")]
    public float CloudsCutoff
    {
        get => _cloudsCutoff;
        set
        {
            _cloudsCutoff = value;
            UpdateClouds();
        }
    }

    private float _cloudsCutoff = 0.3f;

    [Export(PropertyHint.Range, "0,1,0.01")]
    public float CloudsWeight
    {
        get => _cloudsWeight;
        set
        {
            _cloudsWeight = value;
            UpdateClouds();
        }
    }

    private float _cloudsWeight;

    // 是否使用自定义时间代替引擎的TIME
    [Export]
    public bool UseDayTimeForShader
    {
        get => _useDayTimeForShader;
        set
        {
            _useDayTimeForShader = value;
            UpdateShader();
        }
    }

    private bool _useDayTimeForShader;

    // 游戏内时间流速乘数（0时停止，1时1秒=1小时）
    [Export(PropertyHint.Range, "0,1,0.0001")]
    public float TimeScale
    {
        get => _timeScale;
        set => _timeScale = value;
    }

    private float _timeScale = 0.01f;

    // 太阳基础亮度（0时自动获取）
    [Export(PropertyHint.Range, "0,10,0.01")]
    public float SunBaseEnergy
    {
        get => _sunBaseEnergy;
        set
        {
            _sunBaseEnergy = value;
            UpdateShader();
        }
    }

    private float _sunBaseEnergy;

    // 月亮基础亮度（0时自动获取）
    [Export(PropertyHint.Range, "0,10,0.01")]
    public float MoonBaseEnergy
    {
        get => _moonBaseEnergy;
        set
        {
            _moonBaseEnergy = value;
            UpdateShader();
        }
    }

    private float _moonBaseEnergy;

    private WorldEnvironment? _environment;
    private DirectionalLight3D? _sun;
    private DirectionalLight3D? _moon;

    public override void _Ready()
    {
        _environment = GetNode<WorldEnvironment>("WorldEnvironment");
        _sun = GetNode<DirectionalLight3D>("Sun");
        _moon = GetNode<DirectionalLight3D>("Moon");

        if (_sun != null)
        {
            _sun.Position = Vector3.Zero;
            _sun.Rotation = Vector3.Zero;
            // 注意：Godot 4 C# API中可能需要单独设置旋转顺序
            if (SunBaseEnergy == 0.0f)
                SunBaseEnergy = _sun.LightEnergy;
        }

        if (_moon != null)
        {
            _moon.Position = Vector3.Zero;
            _moon.Rotation = Vector3.Zero;
            if (MoonBaseEnergy == 0.0f)
                MoonBaseEnergy = _moon.LightEnergy;
        }

        UpdateAll();
    }

    public override void _Process(double delta)
    {
        if (!Engine.IsEditorHint())
            DayTime += (float)delta * TimeScale;
    }

    private void UpdateAll()
    {
        UpdateSun();
        UpdateMoon();
        UpdateClouds();
        UpdateShader();
    }

    private void UpdateSun()
    {
        if (_sun is null) return;

        var dayProgress = DayTime / HoursInDay;
        _sun.Rotation = new Vector3((float)((dayProgress * 2.0 - 0.5) * -Mathf.Pi), _sun.Rotation.Y, _sun.Rotation.Z);

        var sunDirection = _sun.GlobalTransform.Basis.Z.Normalized();
        _sun.LightEnergy = SmoothStep(-0.05f, 0.1f, sunDirection.Y) * SunBaseEnergy;
    }

    private void UpdateMoon()
    {
        if (_moon == null) return;

        var dayProgress = DayTime / HoursInDay;
        var moonOrbitProgress = (DayOfYear % MoonOrbitalPeriod + dayProgress) / MoonOrbitalPeriod;

        _moon.Rotation = new Vector3(
            ((dayProgress - moonOrbitProgress) * 2.0f - 1.0f) * Mathf.Pi,
            Mathf.DegToRad(MoonOrbitalInclination +
                           PlanetAxialTilt * Mathf.Sin((dayProgress * 2.0f - 1.0f) * Mathf.Pi)),
            Mathf.DegToRad(Latitude)
        );

        var moonDirection = _moon.GlobalTransform.Basis.Z.Normalized();
        _moon.LightEnergy = SmoothStep(-0.05f, 0.1f, moonDirection.Y) * MoonBaseEnergy;
    }

    private void UpdateClouds()
    {
        if (_environment?.Environment?.Sky?.SkyMaterial is not ShaderMaterial shaderMat) return;
        shaderMat.SetShaderParameter("clouds_cutoff", CloudsCutoff);
        shaderMat.SetShaderParameter("clouds_weight", CloudsWeight);
    }

    private void UpdateShader()
    {
        if (_environment?.Environment?.Sky?.SkyMaterial is not ShaderMaterial shaderMat) return;
        var timeValue = UseDayTimeForShader ? (DayOfYear * HoursInDay + DayTime) * 100.0f : 0.0f;
        shaderMat.SetShaderParameter("overwritten_time", timeValue);
    }

    // 自定义SmoothStep实现
    private static float SmoothStep(float edge0, float edge1, float x)
    {
        x = Mathf.Clamp((x - edge0) / (edge1 - edge0), 0.0f, 1.0f);
        return x * x * (3.0f - 2.0f * x);
    }
}